package cn.sell.comm.file;

import com.jcraft.jsch.*;
import lombok.extern.log4j.Log4j2;

import java.io.*;
import java.util.Properties;
import java.util.Vector;

/**
 * @ClasssName: SFTPUpload
 * @description: TODO sftp 操作文件，进行文件的上传下载
 * @Auctior: limi
 * @Date: 2019/7/2415:15
 **/
@Log4j2
public class SFTPUpload {

    public static final String directory = null;
    private static final String host = null;
    private static final int port = 0;
    private static final String username = null;
    private static final String password = null;

    private static ChannelSftp sftp;

    private static SFTPUpload instance = null;

    private SFTPUpload() {
    }

    // 获取接口
    public static SFTPUpload getInstance(String host, int port, String username, String password) {
        instance = new SFTPUpload();
        sftp = instance.connect(host, port, username, password);   //获取连接
        return instance;
    }

    /**
     * 连接sftp服务器
     *
     * @param host     主机
     * @param port     端口
     * @param username 用户名
     * @param password 密码
     * @return
     */
    public ChannelSftp connect(String host, int port, String username, String password) {
        ChannelSftp sftp = null;
        try {
            JSch jsch = new JSch();
            Session sshSession = jsch.getSession(username, host, port);
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            log.info("SFTP Session connected.");
            Channel channel = sshSession.openChannel("sftp");
            channel.connect();
            sftp = (ChannelSftp) channel;
            log.info("连接成功！Connected to " + host);
        } catch (Exception e) {
            log.info("连接失败！Connected to " + host);
            log.info(e);
        }
        return sftp;
    }

    /**
     * 下载单个文件
     *
     * @param directory      ：远程下载目录(以路径符号结束)
     * @param remoteFileName FTP服务器文件名称 如：xxx.txt ||xxx.txt.zip
     * @param localFile      本地文件路径 如 D:\\xxx.txt
     * @return
     * @throws Exception
     */
    public File downloadFile(String directory, String remoteFileName, String localFile) throws Exception {
        log.info(">>>>>>>>FtpUtil-->downloadFile--sftp下载文件" + remoteFileName + "开始>>>>>>>>>>>>>");
        File file = null;
        OutputStream output = null;
        BufferedOutputStream bufferedOutputStream = null;
        try {
            file = new File(localFile);
            if (file.getParentFile() != null && file.getParentFile().exists()) {
                log.info("删除文件夹：{}", file.getParent());
                file.getParentFile().delete();
                if (file.exists()) {
                    int i = localFile.lastIndexOf("/");
                    log.info("要删除的文件为：{}", localFile.substring(i + 1));
                    new File(localFile.substring(i + 1)).delete();
                }
            }
            log.info("开始创建文件夹：{}", file.getParent());
            file.getParentFile().mkdirs();
            log.info("开始创建文件：{}", file.getName());
            file.createNewFile();
            log.info("创建文件成功");
            sftp.cd(directory);
            output = new FileOutputStream(file);
            bufferedOutputStream = new BufferedOutputStream(output);
            sftp.get(remoteFileName, bufferedOutputStream);
            log.info("===DownloadFile:" + remoteFileName + " success from sftp.");
        } catch (SftpException e) {
            if (e.toString().equals("No such file")) {
                log.info(">>>>>>>>FtpUtil-->downloadFile--ftp下载文件失败" + directory + remoteFileName + "不存在>>>>>>>>>>>>>");
                throw new Exception("FtpUtil-->downloadFile--ftp下载文件失败" + directory + remoteFileName + "不存在");
            }
            throw new Exception("ftp目录或者文件异常，检查ftp目录和文件" + e.getMessage());
        } catch (FileNotFoundException e) {
            throw new Exception("本地目录异常，请检查" + file.getPath() + e.getMessage());
        } catch (IOException e) {
            throw new Exception("创建本地文件失败" + file.getPath() + e.getMessage());
        } finally {
            if (bufferedOutputStream != null) {
                try {
                    bufferedOutputStream.close();
                } catch (IOException e) {
                    throw new Exception("Close BufferedOutputStream error." + e.getMessage());
                }
            }
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    throw new Exception("Close FileOutputStream error." + e.getMessage());
                }
            }
        }
        log.info(">>>>>>>>FtpUtil-->downloadFile--ftp下载文件结束>>>>>>>>>>>>>");
        return file;
    }


    /**
     * 上传单个文件
     *
     * @param directory      ：远程下载目录(以路径符号结束)
     * @param uploadFilePath 要上传的文件 如：D:\\test\\xxx.txt
     * @param fileName       FTP服务器文件名称 如：xxx.txt ||xxx.txt.zip
     * @throws Exception
     */
    public void uploadFile(String directory, String uploadFilePath, String fileName)
            throws Exception {
        log.info(">>>>>>>>FtpUtil-->uploadFile--ftp上传文件开始>>>>>>>>>>>>>," +
                        "要上传的路径为：{}," +
                        "要上传的文件：{}" +
                        "文件的新名称为：{}"
                , directory, uploadFilePath, fileName);
        FileInputStream in = null;
        try {
            sftp.cd(directory);
        } catch (SftpException e) {
            try {
                sftp.mkdir(directory);
                sftp.cd(directory);
            } catch (SftpException e1) {
                throw new Exception("ftp创建文件路径失败，路径为" + directory);
            }
        }
        File file = new File(fileName);
        try {
            in = new FileInputStream(file);
            sftp.put(in, fileName);
            file.delete();
        } catch (FileNotFoundException e) {
            throw new Exception("文件不存在-->" + uploadFilePath);
        } catch (SftpException e) {
            throw new Exception("sftp异常-->" + e.getMessage());
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    throw new Exception("Close stream error." + e.getMessage());
                }
            }
        }
        log.info(">>>>>>>>FtpUtil-->uploadFile--ftp上传文件结束>>>>>>>>>>>>>");
    }


    /**
     * 下载文件
     *
     * @param downloadFilePath 下载的文件完整目录
     * @param saveFile         存在本地的路径 + name
     */
    public File download(String downloadFilePath, String saveFile) {
        try {
            int i = downloadFilePath.lastIndexOf('/');
            if (i == -1)
                return null;
            createDir(saveFile.substring(0, i));
            log.info("当前路径为：{}", sftp.pwd());
            File file = new File(saveFile.substring(i + 1));
            if (file.exists()) {
                file.delete();
            }
            file.createNewFile();
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            sftp.get(downloadFilePath.substring(i + 1), fileOutputStream);
            fileOutputStream.close();
            return file;
        } catch (Exception e) {
            log.info(e);
            return null;
        }
    }

    /**
     * 删除文件
     *
     * @param directory  要删除文件所在目录
     * @param deleteFile 要删除的文件
     */
    public void deleteFile(String directory, String deleteFile) {
        try {
            sftp.cd(directory);
            sftp.rm(deleteFile);
        } catch (Exception e) {
            log.info(e.getMessage());
        }
    }

    // 断开sftp连接
    public void disconnect() {
        log.info("断开sftp连接");
        try {
            sftp.getSession().disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        sftp.quit();
        sftp.disconnect();
    }

    // 判断目录是否存在，直接判断完整路径
    public boolean isExistDir(String path) {
        boolean isExist = false;
        try {
            SftpATTRS sftpATTRS = sftp.lstat(path);
            isExist = true;
            return sftpATTRS.isDir();
        } catch (Exception e) {
            e.printStackTrace();
            if (e.getMessage().toLowerCase().equals("no such file")) {
                isExist = false;
            }
        }
        return isExist;
    }

    // 创建目录
    public boolean createDir(String path) {
        boolean s = false;
        try {
            log.info("路径：" + path + "，是否存在" + isExistDir(path));
            if (!isExistDir(path)) {
                sftp.mkdir(path);
                log.info("创建目录成功！");
            }
            s = true;
            sftp.cd(path);
        } catch (SftpException e) {
            e.printStackTrace();
            s = false;
        }
        return s;
    }

    /**
     * 列出目录下的文件
     *
     * @param directory 要列出的目录
     * @throws SftpException
     */
    public Vector<ChannelSftp.LsEntry> listFiles(String directory) throws SftpException {
        Vector ls = sftp.ls(directory);
        return ls;
    }

//    public static void main(String[] args) throws IOException {
//        SFTPUpload sf = SFTPUpload.getInstance();
//        File file = new File("N:\\cms\\05项目规划\\网站认证证书\\pfx-password.txt");
//        sf.upload("/home/test/pass", file, null);    //上传文件
//    }
}
